//https://www.zhangxinxu.com/wordpress/2017/07/js-text-string-download-as-html-json-file/
export function download(content, filename, type = 'text/plain') {
    // 创建隐藏的可下载链接
    var eleLink = document.createElement('a');

    if (!('download' in eleLink)) {
        console.error('this browser donot support client download.');
        return false;
    };

    eleLink.download = filename;
    eleLink.style.display = 'none';
    // 字符内容转变成blob地址
    var blob = new Blob([content], {
        type: type
    });
    eleLink.href = URL.createObjectURL(blob);
    console.log('download in browser\n', eleLink.outerHTML)
    // 触发点击
    document.body.appendChild(eleLink);
    eleLink.click();
    // 然后移除
    document.body.removeChild(eleLink);
};

export function readAsText(file, callback) {
    let reader = new FileReader();
    reader.onload = function() {
        // console.log(this.result)
        if (callback) callback(this.result)
    };
    reader.readAsText(file);
};

var webhost = '';
//is my develop environment
const develophost = 'http://127.0.0.1:8848'
if (document && document.location.href.startsWith(develophost)) {
    webhost = 'http://localhost:80'
} else webhost = '';

var development = webhost !== '';

export {
    webhost,
    development
}

function absUri(url, urlargs) {
    urlargs = urlargs || {};

    let urlquery = [];
    for (let p in urlargs) {
        urlquery.push(p + '=' + encodeURI(urlargs[p]));
    }

    let urlwithArgs = url + (urlquery.length ? (url.indexOf('?') >= 0 ? '&' : '?') + urlquery.join('&') :
        '');

    //for development easily.  
    if (development && !urlwithArgs.startsWith('http://')) urlwithArgs = develophost + '/static' + urlwithArgs;

    return urlwithArgs;
}

export function forward(url, urlargs) {
    let absurl = absUri(url, urlargs);
    // console.log(absurl);
    document.location.href = absurl;
};

export function forwardToLogin() {
    forward('/admin/login.htm', {
        redirect: '/index.htm'
    })
};

export function forwardToHome() {
    forward('/index.htm')
};

export function forwardToErrorMsg(msg, backurl) {
    forward('/errormsg.htm', {
        msg: msg,
        backurl: backurl
    });
};

export function prop2list(obj) {
    let lst = [];
    for (let p in obj) {
        lst.push({
            code: p,
            name: obj[p]
        })
    }
    return lst
}

var hc$data$type$map = {
    'number': '数字',
    'text': '文本',
    'object': '对象'
};

export var hc$data$type$list = prop2list(hc$data$type$map);

export function maxOfProp(array, prop) {
    if (array == undefined || array.length == 0) {
        return 0;
    }

    let max = array[0][prop];
    array.forEach(it => {
        if (max < it[prop]) max = it[prop]
    })

    return max
}

export function removeIf(array, match) {
    if (!array) return array;

    let i = 0;
    while (i < array.length) {
        if (match(array[i])) {
            array.splice(i, 1);
        } else i++;
    }
    return array;
}

export function list(array) {
    let self = {};

    if (!array) array = [];

    self.find = function(match) {

    };

    return self;
}

export function getUrlArgOrDefault(argName, defultVal) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (let i = 0; i < vars.length; i++) {
        let kv = vars[i];
        let equal = kv.indexOf('=');
        let key = kv.substr(0, equal);
        let value = kv.substr(equal + 1);
        if (key === argName) {
            return decodeURI(value);
        }
    }

    console.log(`use ${defultVal} instead of ${argName} url argument in  getUrlArgOrDefault function `)
    return defultVal; //come from code rather than url
}

export function addClass(node, className) {
    if (!node) {
        console.warn('removeClass error!,the node do not exists when adding class of ', className);
        return;
    }

    if (typeof(node) != 'object') node = document.getElementById(node);

    className = ' ' + className.trim();

    let oldClass = node.className;

    if (oldClass.indexOf(className) < 0) {
        node.className = oldClass + className
    }
};

export function removeClass(node, className) {
    if (!node) {
        console.warn('removeClass error! the node does not exit when removing class of ', className)
        return;
    }

    if (typeof(node) != 'object') {
        let nodeid = node;
        node = document.getElementById(nodeid);
        if (!node) {
            console.warn(`removeClass! the dom node of id [${nodeid}] not exits, maybe has been deleted.`);
            return;
        }
    }

    className = ' ' + className.trim();

    let oldClass = node.className

    let index = oldClass.indexOf(className)
    if (index >= 0) {
        node.className = oldClass.substr(0, index) +
            oldClass.substr(index + className.length,
                oldClass.length - className.length
            )
    }
};

export function position(domIdOrDom) {
    let node = typeof(domIdOrDom) === 'object' ? domIdOrDom : document.getElementById(domIdOrDom);
    if (!node) {
        console.warn('document node does not exist.', domIdOrDom);
        return {};
    };
    let style = node.style;

    function _pos(prop) {
        let size = style[prop];
        size = size.substr(0, size.length - 2); //remove 'px'
        return parseInt(size);
    };

    return {
        pos: function(prop) {
            return _pos(prop)
        },
        left: function() {
            return _pos('left')
        },
        top: function() {
            return _pos('top')
        },
        width: function() {
            return _pos('width')
        },
        height: function() {
            return _pos('height')
        },
    };
};

export function ruleTree(pinfo) {
    let ruleList = (pinfo || $pinfo).ruleList.filter(it => it.rtype.startsWith('rule:'));
    let ruleTypes = {};
    ruleList.forEach(it => {
        if (!ruleTypes[it.rtype]) ruleTypes[it.rtype] = [];
        ruleTypes[it.rtype].push({
            // rid: it.rid,
            rpath: it.rpath,
            rname: it.rname,
            rtype: it.rtype,
            nodetype: it.rtype.startsWith('rule:clas:') ? 'switch' : 'task',
            snipCode: `apply(${rpath(it).raccesscode()}.rule)`,
            list: null,
        });
    });

    let ruleTree = [];
    $config.componentList.forEach(it => {
        if (!ruleTypes[it.rtype]) return;
        ruleTree.push({
            // rid: it.rtype,
            rpath:'@'+it.rtype,
            rtype: it.rtype,
            rname: it.rname,
            nodetype: 'category',
            list: ruleTypes[it.rtype],
        });
    });
    return ruleTree;
};

export function clone(object) {
    if (!object) return object;

    return JSON.parse(JSON.stringify(object));
};

/*
Sample:
<input 
onkeyup="value=tokentrim(value)" 
onbeforepaste="clipboardData.setData('text',tokentrim(clipboardData.getData('text')))" ID="Text1" NAME="Text1">
*/
export function tokentrim(input) {
    if (!input) return input;
    input = input.replace(/[^\w\u4E00-\u9FA5]/g, '');
    input = input.replace(/^[\d]+/, "");
    return input;
}

export function tokenvalid(input) {
    return /^[a-zA-Z\u4E00-\u9FA5]{1}[\w\u4E00-\u9FA5]*$/.test(input)
}


//support
//Object.assign(ruleDef,new $util.RpathParser(ruleDef.rpath))
//$util.RpathParser.bind(ruleDef)(ruleDef.rpath)
//ruleDef.rcode()
export function RpathParser(rpath) {
    this.rcode = function() {
        let slash = rpath.lastIndexOf('/');
        return rpath.substring(slash + 1)
    };
    this.rpackage = function() {
        let slash = rpath.lastIndexOf('/');
        return rpath.substring(0, slash).split('/').join('.');
    };

    this.rproject = function() {
        let slash = rpath.indexOf('/');
        return rpath.substr(0, slash);
    };

    this.rfullcode = function() {
        return rpath.split('/').join('.');
    };

    //remove the project prefix and convert to access route for single file script
    this.raccesscode = function() {
        let slash = rpath.indexOf('/');
        return rpath.substr(slash + 1).split('/').join('.');
    };

    //trim the project prefix
    this.rpathInProject = function() {
        let slash = rpath.indexOf('/');
        return rpath.substr(slash + 1);
    };
};

export function rpath(ruleOrPath) {
    let _rpath = typeof(ruleOrPath) === 'string' ? ruleOrPath : ruleOrPath.rpath;
    if (!_rpath) return {};

    return new RpathParser(_rpath);
}

//the tree structure:list[{id/code/name/list}] 
export var $tree = {
    //return: another tree or null
    filter: function(list, condition) {
        if (!list) return null;

        let ret = list.filter(condition);
        ret.forEach(it => {
            it.list = this.filter(it.list, condition);
        });
        return ret;
    },

    //return: node or null
    find: function(list, id, idName = 'id') {
        let loc = this.locate(list, id, idName);
        return loc ? loc.list[loc.index] : null;
    },

    //return: Array or [], node route from root to target
    routeOf: function(list, targetId, tagName = 'id') {
        let itemArray = [];

        _routeOf(list);

        return itemArray;

        function _routeOf(list) {
            if (!list) return false;
            for (let i = 0; i < list.length; i++) {
                let node = list[i];
                if (node[tagName] === targetId) {
                    itemArray.push(node);
                    return true;
                } else {
                    itemArray.push(node);
                    let ret = _routeOf(node.list);
                    if (ret) {
                        return true;
                    } else itemArray.pop();
                }
            };
            return false;
        }
    },

    //return: Array or [], node route from root to target
    route: function(list, tagArray, tagName = 'id') {
        list = list || [];
        tagArray = tagArray || [];

        let index = 0;
        let itemArray = [];

        fetchThis(list, 0);

        return itemArray;

        function fetchThis(lst, depth) {
            if (depth >= tagArray.length) return;

            if (!lst) {
                console.error('Error when fetching in ', list, tagArray);
                return;
            }

            let id = tagArray[depth];

            let finded = lst.find(it => it[tagName] === id);

            itemArray.push(finded);

            if (!finded) {
                console.error('Error when fetching in ', list, tagArray);
                return;
            }

            fetchThis(finded.list, depth + 1);
        };
    },

    //return: {list/index} or null
    locate: function(list, id, idName = 'id') {
        if (!list) return null;
        for (let i = 0; i < list.length; i++) {
            if (list[i][idName] === id) {
                return {
                    list: list,
                    index: i
                };
            } else {
                let finded = this.locate(list[i].list, id, idName);
                if (finded) return finded;
            };
        };
        return null;
    },

    //return: another tree or []
    map: function(list, deal, listName = 'list') {
        if (!list) return null;
        let ret = [];
        list.forEach(it => {
            let n = deal(it);
            ret.push(n);
            if (n) n[listName] = this.map(it.list, deal);
        });
        return ret;
    },

    //return: the tree self
    traverse: function(list, deal) {
        if (!list) return null;
        list.forEach(it => {
            deal(it);
            this.traverse(it.list, deal);
        });

        return list;
    },
    //callback(node,route). route is a [] from root to the current node
    traverseRoute: function(list, callback, childName = 'list') {
        if (!callback) return;
        let route = [];

        traverse(list);

        function traverse(lst) {
            if (!lst) return;
            for (let i in lst) {
                let it = lst[i];
                route.push(it);
                callback(it, route);
                traverse(it[childName]);
                route.pop();
            };
        };
    },

    //TODO
    //traverse with its route info[Node or id Array or id-path]

    //return: another tree, whose content is the same
    clone: function(list) {
        return JSON.parse(JSON.stringify(list));
    },
    enlabel: function(list) {
        this.traverse(list, it => it.label = it.name ? it.code + ':' + it.name : it.code)
    },

    sort: function(list, compare) {
        if (!compare || !list) return list;
        list.sort(compare);
        list.forEach(it => this.sort(it.list, compare));
        return list;
    },
    createId: function(list, idName='id')
    {
        let maxid = 0;
        this.traverse(list,it=>it[idName]=++maxid);
        return list;
    }
};
